import { BaseClient } from '../../client/BaseClient';
import { ParamsStreamScrcpy } from '../../../types/ParamsStreamScrcpy';
import { GoogMoreBox } from '../toolbox/GoogMoreBox';
import { GoogToolBox } from '../toolbox/GoogToolBox';
import VideoSettings from '../../VideoSettings';
import Size from '../../Size';
import { ControlMessage } from '../../controlMessage/ControlMessage';
import { ClientsStats, DisplayCombinedInfo } from '../../client/StreamReceiver';
import { CommandControlMessage } from '../../controlMessage/CommandControlMessage';
import Util from '../../Util';
import FilePushHandler from '../filePush/FilePushHandler';
import DragAndPushLogger from '../DragAndPushLogger';
import { KeyEventListener, KeyInputHandler } from '../KeyInputHandler';
import { KeyCodeControlMessage } from '../../controlMessage/KeyCodeControlMessage';
import { BasePlayer, PlayerClass } from '../../player/BasePlayer';
import GoogDeviceDescriptor from '../../../types/GoogDeviceDescriptor';
import { ConfigureScrcpy } from './ConfigureScrcpy';
import { DeviceTracker } from './DeviceTracker';
import { ControlCenterCommand } from '../../../common/ControlCenterCommand';
import { html } from '../../ui/HtmlTag';
import {
	FeaturedInteractionHandler,
	InteractionHandlerListener,
} from '../../interactionHandler/FeaturedInteractionHandler';
import DeviceMessage from '../DeviceMessage';
import { DisplayInfo } from '../../DisplayInfo';
import { Attribute } from '../../Attribute';
import { HostTracker } from '../../client/HostTracker';
import { ACTION } from '../../../common/Action';
import { StreamReceiverScrcpy } from './StreamReceiverScrcpy';
import { ParamsDeviceTracker } from '../../../types/ParamsDeviceTracker';
import { ScrcpyFilePushStream } from '../filePush/ScrcpyFilePushStream';
import store from '../../../store'
type StartParams = {
	udid : string;
	playerName ?: string;
	player ?: BasePlayer;
	fitToScreen ?: boolean;
	videoSettings ?: VideoSettings;
	show_ToolBox ?: boolean; //云手机右边的操作工具是否显示
	is_master_cloud ?: boolean; //当前设备是否是群控主设备(主要的云手机)
};

const TAG = '[StreamClientScrcpy]';

export class StreamClientScrcpy
	extends BaseClient<ParamsStreamScrcpy, never>
	implements KeyEventListener, InteractionHandlerListener {
	public static ACTION = 'stream';
	private static players : Map<string, PlayerClass> = new Map<string, PlayerClass>();
	private controlButtons ?: HTMLElement;
	private deviceName = '';
	private clientId = -1;
	private clientsCount = -1;
	private joinedStream = false;
	private requestedVideoSettings ?: VideoSettings;
	private touchHandler ?: FeaturedInteractionHandler;
	private moreBox ?: GoogMoreBox;
	public player ?: BasePlayer;
	private filePushHandler ?: FilePushHandler;
	private fitToScreen ?: boolean;
	private show_ToolBox : boolean; // 添加成员变量
	public is_master_cloud : boolean; // 添加成员变量
	private readonly streamReceiver : StreamReceiverScrcpy;
	private lastActivityTime : number = Date.now();
	private idleThreshold : number = 10000;
	private activityCheckInterval ?: number;
	private activityListeners : ((isActive : boolean) => void)[] = [];
	private eventListeners : { element : EventTarget; type : string; handler : () => void }[] = [];
	public addActivityListener(callback : (isActive : boolean) => void) : void {
		this.activityListeners.push(callback);
		if (!this.activityCheckInterval) {
			this.startActivityCheck();
		}
		this.setupActivityListeners(); // 确保监听器已设置
	}

	// 移除监听器
	public removeActivityListener(callback : (isActive : boolean) => void) : void {
		this.activityListeners = this.activityListeners.filter(cb => cb !== callback);
		if (this.activityListeners.length === 0) {
			this.stopActivityCheck();
		}
	}

	// 启动活动检测
	private startActivityCheck() : void {
		this.stopActivityCheck(); // 先停止现有的
		this.activityCheckInterval = window.setInterval(() => {
			const isActive = this.isUserActive();
			this.notifyListeners(isActive);
			if (!isActive) {
				// console.log('用户已空闲超过阈值');
			}
		}, 1000);
	}

	// 停止检测
	private stopActivityCheck() : void {
		if (this.activityCheckInterval) {
			clearInterval(this.activityCheckInterval);
			this.activityCheckInterval = undefined;
		}
	}

	// 通知所有监听器
	private notifyListeners(isActive : boolean) : void {
		this.activityListeners.forEach(cb => {
			try {
				cb(isActive);
			} catch (e) {
				console.error('Activity listener error:', e);
			}
		});
	}

	// 设置空闲阈值
	public setIdleThreshold(ms : number) : void {
		this.idleThreshold = ms;
	}

	// 检查活动状态
	public isUserActive() : boolean {
		return (Date.now() - this.lastActivityTime) <= this.idleThreshold;
	}

	// 更新活动时间
	private updateActivityTime() : void {
		const wasActive = this.isUserActive();
		this.lastActivityTime = Date.now();

		// 状态从不活跃变为活跃时立即通知
		if (!wasActive && this.isUserActive()) {
			this.notifyListeners(true);
		}
	}

	// 初始化事件监听
	private setupActivityListeners() : void {
		// 先清理旧监听器
		this.cleanupEventListeners();

		if (!this.player) return;

		const element = this.player.getTouchableElement();
		if (!element) return;

		const events = ['touchstart', 'touchmove', 'touchend', 'mousedown', 'mousemove', 'click', 'scroll'];
		const handler = () => this.updateActivityTime();

		events.forEach(event => {
			element.addEventListener(event, handler, { passive: true });
			this.eventListeners.push({ element, type: event, handler });
		});
	}

	// 清理事件监听
	private cleanupEventListeners() : void {
		this.eventListeners.forEach(({ element, type, handler }) => {
			element.removeEventListener(type, handler);
		});
		this.eventListeners = [];
	}

	// 销毁时清理资源
	public destroy() : void {
		this.stopActivityCheck();
		this.cleanupEventListeners();
		this.activityListeners = [];
	}

	public static registerPlayer(playerClass : PlayerClass) : void {
		if (playerClass.isSupported()) {
			this.players.set(playerClass.playerFullName, playerClass);
		}
	}

	public static getPlayers() : PlayerClass[] {
		return Array.from(this.players.values());
	}
	public getPlayer() : BasePlayer | undefined {
		return this.player;
	}
	private static getPlayerClass(playerName : string) : PlayerClass | undefined {
		let playerClass : PlayerClass | undefined;
		for (const value of StreamClientScrcpy.players.values()) {
			if (value.playerFullName === playerName || value.playerCodeName === playerName) {
				playerClass = value;
			}
		}
		return playerClass;
	}

	public static createPlayer(playerName : string, udid : string, displayInfo ?: DisplayInfo) : BasePlayer | undefined {
		const playerClass = this.getPlayerClass(playerName);
		if (!playerClass) {
			return undefined;
		}
		return new playerClass(udid, displayInfo);
	}

	public static getFitToScreen(playerName : string, udid : string, displayInfo ?: DisplayInfo) : boolean {
		const playerClass = this.getPlayerClass(playerName);
		if (!playerClass) {
			return false;
		}
		return playerClass.getFitToScreenStatus(udid, displayInfo);
	}
	public static start(
		query : URLSearchParams | ParamsStreamScrcpy,
		streamReceiver ?: StreamReceiverScrcpy,
		player ?: BasePlayer,
		fitToScreen ?: boolean,
		videoSettings ?: VideoSettings,
		show_ToolBox ?: boolean,
		is_master_cloud ?: boolean,
	) : StreamClientScrcpy {
		if (query instanceof URLSearchParams) {
			const params = StreamClientScrcpy.parseParameters(query);
			return new StreamClientScrcpy(params, streamReceiver, player, fitToScreen, videoSettings, show_ToolBox, is_master_cloud);
		} else {
			return new StreamClientScrcpy(query, streamReceiver, player, fitToScreen, videoSettings, show_ToolBox, is_master_cloud);
		}
	}

	private static createVideoSettingsWithBounds(old : VideoSettings, newBounds : Size) : VideoSettings {
		return new VideoSettings({
			crop: old.crop,
			bitrate: old.bitrate,
			bounds: newBounds,
			zoomsize: old.zoomsize,
			maxFps: old.maxFps,
			iFrameInterval: old.iFrameInterval,
			sendFrameMeta: old.sendFrameMeta,
			lockedVideoOrientation: old.lockedVideoOrientation,
			displayId: old.displayId,
			codecOptions: old.codecOptions,
			encoderName: old.encoderName,
		});
	}

	protected constructor(
		params : ParamsStreamScrcpy,
		streamReceiver ?: StreamReceiverScrcpy,
		player ?: BasePlayer,
		fitToScreen ?: boolean,
		videoSettings ?: VideoSettings,
		show_ToolBox : boolean = true,
		is_master_cloud : boolean = false
	) {
		super(params);
		this.show_ToolBox = show_ToolBox; // 初始化成员变量
		this.is_master_cloud = is_master_cloud
		// console.log(params);
		if (streamReceiver) {
			this.streamReceiver = streamReceiver;
		} else {
			this.streamReceiver = new StreamReceiverScrcpy(this.params);
		}
		const { udid, player: playerName } = this.params;
		this.startStream({ udid, player, playerName, fitToScreen, videoSettings, show_ToolBox, is_master_cloud });
		this.setBodyClass('stream');
	}

	public static parseParameters(params : URLSearchParams) : ParamsStreamScrcpy {
		const typedParams = super.parseParameters(params);
		const { action } = typedParams;
		if (action !== ACTION.STREAM_SCRCPY) {
			throw Error('Incorrect action');
		}

		return {
			...typedParams,
			action,
			player: Util.parseString(params, 'player', true),
			udid: Util.parseString(params, 'udid', true),
			ws: Util.parseString(params, 'ws', true),
		};
	}

	public OnDeviceMessage = (message : DeviceMessage) : void => {
		if (this.moreBox) {
			this.moreBox.OnDeviceMessage(message);
		}
	};

	public onVideo = (data : ArrayBuffer) : void => {
		if (!this.player) {
			return;
		}
		const STATE = BasePlayer.STATE;
		if (this.player.getState() === STATE.PAUSED) {
			this.player.play();
		}
		if (this.player.getState() === STATE.PLAYING) {
			this.player.pushFrame(new Uint8Array(data));
		}
	};

	public onClientsStats = (stats : ClientsStats) : void => {
		this.deviceName = stats.deviceName;
		this.clientId = stats.clientId;
		this.setTitle(`Stream ${this.deviceName}`);
	};
	public onDisplayInfo = (infoArray : DisplayCombinedInfo[]) : void => {
		if (!this.player) {
			return;
		}
		let currentSettings = this.player.getVideoSettings();
		const displayId = currentSettings.displayId;
		const info = infoArray.find((value) => {
			return value.displayInfo.displayId === displayId;
		});
		if (!info) {
			return;
		}
		if (this.player.getState() === BasePlayer.STATE.PAUSED) {
			this.player.play();
		}
		const { videoSettings, screenInfo } = info;
		this.player.setDisplayInfo(info.displayInfo);
		if (typeof this.fitToScreen !== 'boolean') {
			this.fitToScreen = this.player.getFitToScreenStatus();
		}
		if (this.fitToScreen) {
			const newBounds = this.getMaxSize();
			if (newBounds) {
				currentSettings = StreamClientScrcpy.createVideoSettingsWithBounds(currentSettings, newBounds);
				this.player.setVideoSettings(currentSettings, this.fitToScreen, false);
			}
		}
		if (!videoSettings || !screenInfo) {
			this.joinedStream = true;
			this.sendMessage(CommandControlMessage.createSetVideoSettingsCommand(currentSettings));
			return;
		}

		this.clientsCount = info.connectionCount;
		let min = VideoSettings.copy(videoSettings);
		const oldInfo = this.player.getScreenInfo();
		if (!screenInfo.equals(oldInfo)) {
			this.player.setScreenInfo(screenInfo);
		}

		if (!videoSettings.equals(currentSettings)) {
			this.applyNewVideoSettings(videoSettings, videoSettings.equals(this.requestedVideoSettings));
		}
		if (!oldInfo) {
			const bounds = currentSettings.bounds;
			const videoSize : Size = screenInfo.videoSize;
			const onlyOneClient = this.clientsCount === 0;
			const smallerThenCurrent = bounds && (bounds.width < videoSize.width || bounds.height < videoSize.height);
			if (onlyOneClient || smallerThenCurrent) {
				min = currentSettings;
			}
			const minBounds = currentSettings.bounds?.intersect(min.bounds);
			if (minBounds && !minBounds.equals(min.bounds)) {
				min = StreamClientScrcpy.createVideoSettingsWithBounds(min, minBounds);
			}
		}
		if (!min.equals(videoSettings) || !this.joinedStream) {
			this.joinedStream = true;
			this.sendMessage(CommandControlMessage.createSetVideoSettingsCommand(min));
		}
	};

	public onDisconnected = () : void => {
		this.streamReceiver.off('deviceMessage', this.OnDeviceMessage);
		this.streamReceiver.off('video', this.onVideo);
		this.streamReceiver.off('clientsStats', this.onClientsStats);
		this.streamReceiver.off('displayInfo', this.onDisplayInfo);
		this.streamReceiver.off('disconnected', this.onDisconnected);
		this.filePushHandler?.release();
		this.filePushHandler = undefined;
		this.touchHandler?.release();
		this.touchHandler = undefined;
		this.streamReceiver.stop()
		if (this.activityCheckInterval) {
			clearInterval(this.activityCheckInterval);
			this.activityCheckInterval = undefined;
		}
	};

	public startStream({ udid, player, playerName, videoSettings, fitToScreen, show_ToolBox, is_master_cloud } : StartParams) : void {
		if (!udid) {
			throw Error(`Invalid udid value: "${udid}"`);
		}

		this.fitToScreen = fitToScreen;
		if (!player) {
			if (typeof playerName !== 'string') {
				throw Error('Must provide BasePlayer instance or playerName');
			}
			let displayInfo : DisplayInfo | undefined;
			if (this.streamReceiver && videoSettings) {
				displayInfo = this.streamReceiver.getDisplayInfo(videoSettings.displayId);
			}
			const p = StreamClientScrcpy.createPlayer(playerName, udid, displayInfo);
			if (!p) {
				throw Error(`Unsupported player: "${playerName}"`);
			}
			if (typeof fitToScreen !== 'boolean') {
				fitToScreen = StreamClientScrcpy.getFitToScreen(playerName, udid, displayInfo);
			}
			player = p;
		}
		this.player = player;
		this.setTouchListeners(player);

		if (!videoSettings) {
			videoSettings = player.getVideoSettings();
		}

		const deviceView = document.createElement('div');
		deviceView.className = 'device-view';
		const stop = (ev ?: string | Event) => {
			if (ev && ev instanceof Event && ev.type === 'error') {
				console.error(TAG, ev);
			}
			let parent;
			parent = deviceView.parentElement;
			if (parent) {
				parent.removeChild(deviceView);
			}
			parent = moreBox.parentElement;
			if (parent) {
				parent.removeChild(moreBox);
			}
			this.streamReceiver.stop();
			if (this.player) {
				this.player.stop();
			}
		};
		const googMoreBox = (this.moreBox = new GoogMoreBox(udid, player, this));
		const moreBox = googMoreBox.getHolderElement();
		googMoreBox.setOnStop(stop);
		if (show_ToolBox) {
			const googToolBox = GoogToolBox.createToolBox(udid, player, this, moreBox);
			this.controlButtons = googToolBox.getHolderElement();
			deviceView.appendChild(this.controlButtons);
		}
		const video = document.createElement('div');
		video.className = 'video';
		deviceView.appendChild(video);
		deviceView.appendChild(moreBox);
		player.setParent(video);
		player.pause();
		const appElement = document.getElementById(`phone-display-${udid}`);
		if (appElement) {
			appElement.innerHTML = '';
			appElement.appendChild(deviceView);
			// 确保容器样式正确
			appElement.style.position = 'relative';
			appElement.style.width = '100%';
			appElement.style.height = '100%';
			appElement.appendChild(deviceView);
		} else {
			console.error('Could not find element with id "phone-display"');
			document.body.appendChild(deviceView); // 回退方案
		}

		if (fitToScreen) {
			const newBounds = this.getMaxSize();
			if (newBounds) {
				videoSettings = StreamClientScrcpy.createVideoSettingsWithBounds(videoSettings, newBounds);
			}
		}
		this.applyNewVideoSettings(videoSettings, false);
		const element = player.getTouchableElement();
		const logger = new DragAndPushLogger(element);
		this.filePushHandler = new FilePushHandler(element, new ScrcpyFilePushStream(this.streamReceiver));
		this.filePushHandler.addEventListener(logger);

		const streamReceiver = this.streamReceiver;
		streamReceiver.on('deviceMessage', this.OnDeviceMessage);
		streamReceiver.on('video', this.onVideo);
		streamReceiver.on('clientsStats', this.onClientsStats);
		streamReceiver.on('displayInfo', this.onDisplayInfo);
		streamReceiver.on('disconnected', this.onDisconnected);
		this.setupActivityListeners();
	}
	public sendMessage(message : ControlMessage) : void {
		this.streamReceiver.sendEvent(message);
	}

	public getDeviceName() : string {
		return this.deviceName;
	}

	public setHandleKeyboardEvents(enabled : boolean) : void {
		if (enabled) {
			KeyInputHandler.addEventListener(this);
		} else {
			KeyInputHandler.removeEventListener(this);
		}
		store.dispatch('updateLocalKeyboard', {
			udid: this.player?.udid,  // 第一个参数（udid）
			data: enabled       // 第二个参数（开关状态）
		})
	}

	public onKeyEvent(event : KeyCodeControlMessage) : void {
		this.updateActivityTime();
		this.sendMessage(event);
	}

	public sendNewVideoSetting(videoSettings : VideoSettings) : void {
		this.requestedVideoSettings = videoSettings;
		this.sendMessage(CommandControlMessage.createSetVideoSettingsCommand(videoSettings));
	}

	public getClientId() : number {
		return this.clientId;
	}

	public getClientsCount() : number {
		return this.clientsCount;
	}

	public getMaxSize() : Size | undefined {
		if (!this.controlButtons) {
			return undefined;
		}
		const body = document.body;
		const width = (body.clientWidth - this.controlButtons.clientWidth) & ~15;
		const height = body.clientHeight & ~15;
		return new Size(width, height);
	}

	private setTouchListeners(player : BasePlayer) : void {
		if (this.touchHandler) {
			return;
		}
		this.touchHandler = new FeaturedInteractionHandler(player, this);
	}

	private applyNewVideoSettings(videoSettings : VideoSettings, saveToStorage : boolean) : void {
		let fitToScreen = false;

		// TODO: create control (switch/checkbox) instead
		if (videoSettings.bounds && videoSettings.bounds.equals(this.getMaxSize())) {
			fitToScreen = true;
		}
		if (this.player) {
			this.player.setVideoSettings(videoSettings, fitToScreen, saveToStorage);
		}
	}

	public static createEntryForDeviceList(
		descriptor : GoogDeviceDescriptor,
		blockClass : string,
		fullName : string,
		params : ParamsDeviceTracker,
	) : HTMLElement | DocumentFragment | undefined {
		const hasPid = descriptor.pid !== -1;
		if (hasPid) {
			const configureButtonId = `configure_${Util.escapeUdid(descriptor.udid)}`;
			const e = html`<div class="stream ${blockClass}">
                <button
                    ${Attribute.UDID}="${descriptor.udid}"
                    ${Attribute.COMMAND}="${ControlCenterCommand.CONFIGURE_STREAM}"
                    ${Attribute.FULL_NAME}="${fullName}"
                    ${Attribute.SECURE}="${params.secure}"
                    ${Attribute.HOSTNAME}="${params.hostname}"
                    ${Attribute.PORT}="${params.port}"
                    ${Attribute.PATHNAME}="${params.pathname}"
                    ${Attribute.USE_PROXY}="${params.useProxy}"
                    id="${configureButtonId}"
                    class="active action-button"
                >
                    Configure stream
                </button>
            </div>`;
			const a = e.content.getElementById(configureButtonId);
			a && (a.onclick = this.onConfigureStreamClick);
			return e.content;
		}
		return;
	}

	private static onConfigureStreamClick = (event : MouseEvent) : void => {
		const button = event.currentTarget as HTMLAnchorElement;
		const udid = Util.parseStringEnv(button.getAttribute(Attribute.UDID) || '');
		const fullName = button.getAttribute(Attribute.FULL_NAME);
		const secure = Util.parseBooleanEnv(button.getAttribute(Attribute.SECURE) || undefined) || false;
		const hostname = Util.parseStringEnv(button.getAttribute(Attribute.HOSTNAME) || undefined) || '';
		const port = Util.parseIntEnv(button.getAttribute(Attribute.PORT) || undefined);
		const pathname = Util.parseStringEnv(button.getAttribute(Attribute.PATHNAME) || undefined) || '';
		const useProxy = Util.parseBooleanEnv(button.getAttribute(Attribute.USE_PROXY) || undefined);
		if (!udid) {
			throw Error(`Invalid udid value: "${udid}"`);
		}
		if (typeof port !== 'number') {
			throw Error(`Invalid port type: ${typeof port}`);
		}
		const tracker = DeviceTracker.getInstance({
			type: 'android',
			secure,
			hostname,
			port,
			pathname,
			useProxy,
		});
		const descriptor = tracker.getDescriptorByUdid(udid);
		if (!descriptor) {
			return;
		}
		event.preventDefault();
		const elements = document.getElementsByName(`${DeviceTracker.AttributePrefixInterfaceSelectFor}${fullName}`);
		if (!elements || !elements.length) {
			return;
		}
		const select = elements[0] as HTMLSelectElement;
		const optionElement = select.options[select.selectedIndex];
		const ws = optionElement.getAttribute(Attribute.URL);
		const name = optionElement.getAttribute(Attribute.NAME);
		if (!ws || !name) {
			return;
		}
		const options : ParamsStreamScrcpy = {
			udid,
			ws,
			player: '',
			action: ACTION.STREAM_SCRCPY,
			secure,
			hostname,
			port,
			pathname,
			useProxy,
		};
		const dialog = new ConfigureScrcpy(tracker, descriptor, options);
		dialog.on('closed', StreamClientScrcpy.onConfigureDialogClosed);
	};

	private static onConfigureDialogClosed = (event : { dialog : ConfigureScrcpy; result : boolean }) : void => {
		event.dialog.off('closed', StreamClientScrcpy.onConfigureDialogClosed);
		if (event.result) {
			HostTracker.getInstance().destroy();
		}
	};
}